#pragma once
#include "PDTStatement.h"
#include "PDTVar.h"
#include "PDTExp.h"
#include "PDTBoolConst.h"

class PDTCondition: public PDTStatement {
protected:
	string name;
public:
	PDTCondition(PDTCodeGraph & CG, PDTExpBool & exp, const string & aName):
		PDTStatement(CG), name(aName) {
		addChild(&exp);
		exp.addParent(this);
	}

	string getName() const{
		return name;
	}

	void setName(string & aName) {
		name = aName;
	}

	PDTExpBool* getExpression() const {
		return dynamic_cast<PDTExpBool*> (children[0]);
	}

	virtual NodeTypeEnum getType() {
		return PDTCondition_Em;
	}

	bool isCondition() {
		return true;
	}

	virtual stringstream & toString(stringstream & ss) const {
		ss << " ";
		return ss;
	}
};

class PDTPreCondition :  public PDTCondition, public TraverseIfc <PDTPreCondition, PDTNode> { public:  TRAVERSAL_IFC_IMPL(PDTPreCondition)
public:
	PDTPreCondition(PDTCodeGraph & CG, PDTExpBool & exp, string & aName) :
		PDTCondition(CG, exp, aName) {
	}

	NodeTypeEnum getType() {
		return PDTPreCondition_Em;
	}

	bool isPreCondition() {
		return true;
	}

	virtual bool eval(PDTCodeGraph &CG)
	{
	    getExpression()->eval(CG);
	    bool result = (dynamic_cast<PDTBoolConst*>(getExpression()->nValue))->getValue();
	    nValue = new PDTBoolConst(CG, result);
	    cout<<"-----------------------------"<<endl;
	    cout<<"Pre-Condition evaluated to: "<<result<<endl;
	    cout<<"-----------------------------"<<endl;
	    return true;
	}

	virtual stringstream & toString(stringstream & ss) const {
		ss << "@pre ";
		ss << getName() << " ( ";
		getExpression()->toString(ss);
		ss << ")";
		return ss;
	}
};

class PDTPostCondition :  public PDTCondition, public TraverseIfc <PDTPostCondition, PDTNode> { public:  TRAVERSAL_IFC_IMPL(PDTPostCondition)
public:
	PDTPostCondition(PDTCodeGraph & CG, PDTExpBool & exp, string & aName) :
		PDTCondition(CG, exp, aName) {
	}

	NodeTypeEnum getType() {
		return PDTPostCondition_Em;
	}

	bool isPostCondition() {
		return true;
	}

	virtual bool eval(PDTCodeGraph &CG)
	{
	    getExpression()->eval(CG);
	    bool result = (dynamic_cast<PDTBoolConst*>(getExpression()->nValue))->getValue();
	    nValue = new PDTBoolConst(CG, result);
	    cout<<"-------------------------------"<<endl;
	    cout<<"Post-Condition evaluated to: "<<result<<endl;
	    cout<<"-------------------------------"<<endl;
	    return true;
	}

	virtual stringstream & toString(stringstream & ss) const {
	    ss << "@post ";
	    ss << getName() << " ( ";
	    getExpression()->toString(ss);
	    ss << ")";
	    return ss;
	}
};

class PDTInvariant :  public PDTCondition, public TraverseIfc <PDTInvariant, PDTNode> { public:  TRAVERSAL_IFC_IMPL(PDTInvariant)
public:
	PDTInvariant(PDTCodeGraph & CG, PDTExpBool & exp, string & aName) :
		PDTCondition(CG, exp, aName) {
	}

	NodeTypeEnum getType() {
		return PDTInvariant_Em;
	}

	bool isInvariant() {
		return true;
	}

	virtual stringstream & toString(stringstream & ss) const {
		ss << "@I ";
		ss << getName() << " ( ";
		getExpression()->toString(ss);
		ss << ")";
		return ss;
	}
};
